﻿
Imports std
Imports storoomc
Imports storcore

'treat each storoom/stornode managed by storoom as the same, write / modify / delete, etc to all.
'and read from a single node
Public Class nodes_redundance
    Inherits storoomOper

    Public Overrides Function showslice(ByVal slice As storageInterface) As String
        Return common.showslice(slice)
    End Function

    Protected Overridable Function slicehealth(ByVal slice As storageInterface) As Boolean
        Dim hslice As storageInterface = Nothing
        Dim node As stornode = Nothing
        node = convertor.cast(Of stornode)(slice)

        Dim rndstart As Int64
        rndstart = rnd(0, slices.size(), True)
        Dim i As Int64
        i = rndstart
        Dim found As Boolean = False
        Do
            'though the input slice should not be health slice during slicehealth call,
            'but to make it safer, add this chek
            If Not Object.ReferenceEquals(slices(i), slice) Then
                hslice = slices(i)
                If ishealthSlice(hslice) AndAlso hslice.sync(node.host, node.port) Then
                    raiseError("found an slice returns health, finish sync.")
                    found = True
                    Exit Do
                End If
            End If

            i += 1
            If i >= slices.size() Then
                i = 0
            End If
        Loop Until i = rndstart

        If Not found Then
            raiseError("cannot get a health slice to sync to failed slice.", errorHandle.errorType.exclamation)
            Return False
        Else
            Return True
        End If
    End Function

    Protected Sub startImpl(ByVal forceDisableCache As Boolean)
        If forceDisableCache Then
            enablecache = False
        End If
        MyBase.start()
        'manually call a slicesCleaner, to set unhealth slice. before each stornode ready to serve.
        slicesCleanerImpl()

        'sleep until normal slices count >= 1/2
        Dim sc As Int64 = 0
        Dim usc As Int64 = 0
        While True
            status(sc, usc)
            If sc = 0 OrElse Convert.ToDouble(usc) / sc > 1 / 2 Then
                sleepSeconds(30)
            Else
                Exit While
            End If
        End While

        sliceHealthHandle = AddressOf slicehealth
    End Sub

    Public Overrides Sub start()
        nodesStart(Me)
        'force disable cache in redundancy mode, as the sync operation is async.
        'before all data has been synced to broken stornode, storoom will think the stornode is health.
        startImpl(True)
    End Sub

    Protected Overridable Function write_redundancy(ByVal key As String, ByVal buff As bytes) As Boolean
        Return threadModel().multiOper(d(Function(ByRef s As storageInterface) As ternary
                                             Return s.write(key, buff)
                                         End Function), slices)
    End Function

    Protected NotOverridable Overrides Function writeImpl(ByVal key As String, ByVal buff As bytes, _
                                                          ByRef slice As storageInterface, _
                                                          ByVal slices As vector(Of storageInterface)) As Boolean
        Return write_redundancy(key, buff)
    End Function

    Protected Overridable Function modify_redundancy(ByVal key As String, ByVal buff As bytes) As Boolean
        Return threadModel().multiOper(d(Function(ByRef s As storageInterface) As ternary
                                             Return s.modify(key, buff)
                                         End Function), slices)
    End Function

    Protected NotOverridable Overrides Function modifyImpl(ByVal key As String, ByVal buff As bytes, _
                                                           ByRef slice As storageInterface, _
                                                           ByVal slices As vector(Of storageInterface)) As Boolean
        Return modify_redundancy(key, buff)
    End Function

    Protected NotOverridable Overrides Function selectKeySlices(ByVal key As String) As vector(Of storageInterface)
        Return selectSlices()
    End Function

    Protected NotOverridable Overrides Function selectSlices() As vector(Of storageInterface)
        Dim rtn As vector(Of storageInterface) = Nothing
        rtn = New vector(Of storageInterface)()
        rtn.push_back(randomSlice(slices, Nothing))
        Return rtn
    End Function

    Protected NotOverridable Overrides Function writeSelectSlices(ByVal key As String) As vector(Of storageInterface)
        Return slices
    End Function

    Protected NotOverridable Overrides Function modifySelectSlices(ByVal key As String) As vector(Of storageInterface)
        Return slices
    End Function

    Protected NotOverridable Overrides Function syncSelectSlices() As vector(Of storageInterface)
        Return selectSlices()
    End Function

    Protected NotOverridable Overrides Function deleteSelectSlices(ByVal key As String) As vector(Of storageInterface)
        Return slices
    End Function

    Protected NotOverridable Overrides Function fullSelectSlices() As vector(Of storageInterface)
        Return slices
    End Function

    Protected NotOverridable Overrides Function capacitySelectSlices() As vector(Of storageInterface)
        Return slices
    End Function

    Protected NotOverridable Overrides Function fullImpl(ByVal slices As vector(Of storageInterface)) As ternary
        Return shareTypeFull(slices)
    End Function

    Protected NotOverridable Overrides Function capacityImpl(ByRef cap As UInt64, _
                                                             ByVal slices As vector(Of storageInterface)) As Boolean
        Return shareTypeCapacity(cap, slices)
    End Function
End Class
